package com.elitel.frame.main.security;

import com.elitel.frame.base.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * TODO: Spring Security 配置
 *
 * @since 2020-02-18
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private JwtTokenAuthorizationFilter jwtTokenAuthorizationFilter;
    @Autowired
    private UserInfoService customUserService;

    @Value("${authorize.enable}")
    private boolean securityEnable;

    /**
     * 密码加密器
     *
     * @return
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public AuthenticationProvider authenticationProvider() {
        AuthenticationProvider authenticationProvider = new CustomAuthenticationProvider();
        return authenticationProvider;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(customUserService);
        auth.authenticationProvider(authenticationProvider());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.cors().and()
                .csrf()
                .disable().authorizeRequests()
                .requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
                .and()
                .headers()
                .frameOptions()
                .disable()// 用于解决嵌入 iframe 禁用 X-Frame-Options
                .cacheControl(); // 禁用 Http 头部缓存

        if (securityEnable) {
            http.formLogin()
                    // 登录失败响应事件
                    .failureHandler(
                            (HttpServletRequest request,
                             HttpServletResponse response,
                             AuthenticationException ex) -> {
                                response.setCharacterEncoding("UTF-8");
                                response.getWriter().print("{\"success\": false }");
                            })
                    //定义登录页面，访问一个需要登录之后才能访问的接口时，会自动跳转到该页面
                    .loginPage("/login")
                    //定义登录时，用户名的 key，默认为 username
                    .usernameParameter("username")
                    //定义登录时，用户密码的 key，默认为 password
                    .passwordParameter("password")
                    .loginProcessingUrl("/authentication/form")
                    .defaultSuccessUrl("/")
                    .permitAll()

                    // 设置未授权返回信息
                    .and()
                    .exceptionHandling()
                    .authenticationEntryPoint(
                            (HttpServletRequest request,
                             HttpServletResponse response,
                             AuthenticationException var3) -> {
                                String requestURI = request.getRequestURI();
                                String ajaxFlag = request.getHeader("X-Requested-With");
                                if ((ajaxFlag != null && "XMLHttpRequest".equals(ajaxFlag))
                                        || requestURI.startsWith("/business")) {
                                    response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
                                } else {
                                    response.sendRedirect("/login");
                                }
                            })
                    .and()
                    .logout()
                    .permitAll()
                    .and()
                    .authorizeRequests()
                    .antMatchers(
                            "/login",
                            "/testAjax",
                            "/system/authorization/token/**",
                            "/plugins/**",
                            "/metronic/**",
                            "/assets/**")
                    .permitAll() // 所有用户均可访问资源
                    .anyRequest()
                    .authenticated()
                    .and()
                    .addFilterAfter(jwtTokenAuthorizationFilter, UsernamePasswordAuthenticationFilter.class);
        }
    }
}
